package com.iwdnb.gkgz.controller;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSONObject;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.iwdnb.bmnf.common.dingtalk.DingTalkMessage;
import com.iwdnb.bmnf.common.dingtalk.DingTalkMessage.At;
import com.iwdnb.bmnf.common.dingtalk.DingTalkMessage.Markdown;
import com.iwdnb.bmnf.common.dingtalk.DingTalkService;
import com.iwdnb.bmnf.common.model.OrderBy;
import com.iwdnb.bmnf.common.model.Page;
import com.iwdnb.bmnf.common.model.PageData;
import com.iwdnb.bmnf.common.model.dto.UploadFileDTO;
import com.iwdnb.bmnf.common.model.result.Result;
import com.iwdnb.bmnf.common.utils.HttpClientUtils;
import com.iwdnb.bmnf.common.utils.ServletRequestUtils;
import com.iwdnb.gkgz.application.model.vo.StockKlineData;
import com.iwdnb.gkgz.application.service.StockEmotionService;
import com.iwdnb.gkgz.common.model.dto.StockEmotion;
import com.iwdnb.gkgz.common.model.dto.StockSignalDTO;
import com.iwdnb.gkgz.common.model.dto.StrategyTradeDTO;
import com.iwdnb.gkgz.common.quota.HullMovingAverage;
import com.iwdnb.gkgz.common.quota.HullMovingAverage.HullAverageData;
import com.iwdnb.gkgz.application.service.StockChartService;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.quota.MovingAverage;
import com.iwdnb.gkgz.common.quota.OBVIndicator;
import com.iwdnb.gkgz.common.quota.RSIIndicator;
import com.iwdnb.gkgz.common.utils.BigDecimalUtils;
import com.iwdnb.gkgz.common.utils.DateUtils;
import com.iwdnb.gkgz.common.utils.StockRangeUtils;
import com.iwdnb.gkgz.common.utils.StockUtils;
import com.iwdnb.gkgz.infrastructure.dao.repo.StockDayDataRepository;
import com.iwdnb.gkgz.infrastructure.dao.repo.StockRepository;
import com.iwdnb.wwzy.dao.MetaDataDAO;
import com.iwdnb.wwzy.model.query.MetaQuery;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import static com.iwdnb.gkgz.common.constant.GkgzConstants.OBJECT_CODE_STOCK_SIGNAL;
import static com.iwdnb.gkgz.common.constant.GkgzConstants.OBJECT_CODE_STRATEGY_TRADE;

/**
 * K线图
 */
@Controller
@RequestMapping("/api/stock/chart")
@Slf4j
public class StockChartController {

    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private StockChartService stockChartService;
    @Autowired
    private StockDayDataRepository stockDayDataRepository;
    @Autowired
    private MetaDataDAO metaDataDAO;
    @Autowired
    private StockEmotionService stockEmotionService;
    @Autowired
    private DingTalkService dingTalkService;

    private String UPLOAD_URL = "https://pagan.gongdao.com/api/fileOperation/upload?token=123456";

    private String DOWNLOAD_URL
        = "https://pagan.gongdao.com/api/fileOperation/downloadByResourceId?resourceId=%s&token=123456";

    private String DING_TALK_URL = "https://oapi.dingtalk"
        + ".com/robot/send?access_token=a079cbbaa764379fb898c2c16bd9be407966dfba41e19f5b25a7b015240c0901";

    /**
     * 股票K线图页面
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/index")
    public String index(String code, String shape) {
        return "stockChart";
    }

    /**
     * 获取股票指定形态的日线数据
     * eg:/api/stock/chart/index?code=sz300210&date=2013-12-05&period=100
     * eg:/api/stock/chart/index?code=sz300210&uuid=202403120001
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/getStockKlineData")
    @ResponseBody
    public List<StockKlineData> getStockKlineData(String code, String date, Integer period, String uuid) {
        List<StockDayData> stockDayDataList = null;
        if (Objects.nonNull(uuid)) {
            stockDayDataList = stockChartService.getStockKlineData(code, uuid);
        } else {
            stockDayDataList = stockChartService.getStockKlineData(code, date, period);
        }
        List<StockKlineData> klineDatas = new ArrayList<>();
        StockDayData old = stockDayDataList.get(0);
        int index = 0;
        for (StockDayData data : stockDayDataList) {
            List kline = new ArrayList();
            kline.add(data.getOpenPrice());
            kline.add(data.getClosePrice());
            kline.add(data.getMinPrice());
            kline.add(data.getMaxPrice());
            kline.add(
                Objects.nonNull(data.getTradeNum()) ? data.getTradeNum().intValue() : old.getTradeNum().intValue());
            StockKlineData klineData = new StockKlineData();
            klineData.setData(data);
            klineData.setValue(kline);
            klineData.setStockDate(data.getDate());
            klineData.setVolume((Integer)kline.get(4));
            klineData.setUpOrDown(data.getClosePrice().compareTo(old.getClosePrice()) > 0 ? "y" : "n");
            klineData.setIndex(index);
            BigDecimal range = BigDecimalUtils.subtract(data.getClosePrice(), old.getClosePrice());
            BigDecimal rate = BigDecimalUtils.divideToPrecent(range, old.getClosePrice());
            klineData.setRate(rate);
            if (StringUtils.isNotBlank(data.getMark())) {
                klineData.setMark(data.getMark());
            }
            klineDatas.add(klineData);
            old = data;
            if (BigDecimalUtils.eq(old.getClosePrice(), BigDecimal.ZERO)) {
                old.setClosePrice(new BigDecimal("0.01"));
            }
            index++;
        }
        return klineDatas;
    }

    /**
     * 股票均线线图页面
     *
     * @return
     */
    @GetMapping(value = "/stockAverageChart")
    public String stockAverageChart() {
        return "stockAverageChart";
    }

    /**
     * 获取股票指定形态的日线数据
     * eg:/api/stock/chart/stockAverageChart?code=sz300210&period=13&longPeriod=13
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/getStockAveragelineData")
    @ResponseBody
    public List<StockKlineData> getStockAveragelineData(String code, Integer period, Integer longPeriod, String date) {
        if (Objects.isNull(period)) {
            period = 21;
        }
        if (Objects.isNull(longPeriod)) {
            longPeriod = 88;
        }
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(code);
        if (StringUtils.isNotBlank(date)) {
            Date d = DateUtil.parseDate(date);
            Date begin = DateUtil.offsetDay(d, -300);
            Date end = DateUtil.offsetDay(d, 300);
            stockDayDataList = StockUtils.getStockDayDataListByDateRange(stockDayDataList, begin, end);
            for (StockDayData stockDayData : stockDayDataList) {
                if (stockDayData.getDate().equals(date)) {
                    stockDayData.setMark("涨");
                    break;
                }
            }
        }
        List<StockKlineData> klineDatas = new ArrayList<>();
        StockDayData old = stockDayDataList.get(0);
        int index = 0;
        List<HullAverageData> averageDataList = HullMovingAverage.calculateHMA(stockDayDataList, period);
        List<HullAverageData> longAverageDataList = HullMovingAverage.calculateHMA(stockDayDataList, longPeriod);
        List<HullAverageBias> biasList = new ArrayList<>();
        for (StockDayData data : stockDayDataList) {
            List kline = new ArrayList();
            kline.add(data.getOpenPrice());
            kline.add(data.getClosePrice());
            kline.add(data.getMinPrice());
            kline.add(data.getMaxPrice());
            kline.add(
                Objects.nonNull(data.getTradeNum()) ? data.getTradeNum().intValue() : old.getTradeNum().intValue());
            StockKlineData klineData = new StockKlineData();
            klineData.setCode(code);
            klineData.setData(data);
            klineData.setValue(kline);
            klineData.setStockDate(data.getDate());
            klineData.setVolume((Integer)kline.get(4));
            klineData.setUpOrDown(data.getClosePrice().compareTo(old.getClosePrice()) > 0 ? "y" : "n");
            klineData.setIndex(index);
            BigDecimal rate = data.getClosePrice().subtract(old.getClosePrice()).multiply(new BigDecimal(100)).divide(
                old.getClosePrice(), BigDecimal.ROUND_HALF_DOWN).setScale(2, RoundingMode.HALF_DOWN);
            klineData.setRate(rate);
            if (StringUtils.isNotBlank(data.getMark())) {
                klineData.setMark(data.getMark());
            }
            HullAverageBias bias = new HullAverageBias();
            bias.setDate(data.getDate());
            HullAverageData averageData = averageDataList.stream().filter(
                hullAverageData -> hullAverageData.getDate().equals(data.getDate())).findAny().orElse(null);
            if (Objects.nonNull(averageData)) {
                klineData.setShortAverageData(averageData.getPrice());
                bias.setShortBias(averageData.getBias());
            }
            HullAverageData longAverageData = longAverageDataList.stream().filter(
                hullAverageData -> hullAverageData.getDate().equals(data.getDate())).findAny().orElse(null);
            if (Objects.nonNull(longAverageData)) {
                klineData.setLongAverageData(longAverageData.getPrice());
                bias.setLongBias(longAverageData.getBias());
            }
            klineDatas.add(klineData);
            biasList.add(bias);
            old = data;
            index++;
        }
        //log.info("biasData:" + JSON.toJSONString(biasList));
        return klineDatas;
    }

    /**
     * 股票涨停板走势页面
     *
     * @return
     */
    @GetMapping(value = "/stockLimitUpChart")
    public String stockLimitUpChart() {
        return "stockLimitUpChart";
    }

    /**
     * 获取股票指定形态的日线数据
     * eg:/api/stock/chart/stockLimitUpChart?strategy=arxhz&index=0&period=88
     *
     * @param
     * @return
     */
    @GetMapping(value = "/getStockLimitUpLineData")
    @ResponseBody
    public List<StockKlineData> getStockLimitUpLineData(String strategy, Integer period, Integer index,
        String orderField, String sort, String code) {
        if (Objects.isNull(period)) {
            period = 100;
        }
        if (Objects.isNull(index)) {
            index = 0;
        }
        if (StringUtils.isBlank(orderField)) {
            orderField = "profit_rate";
        }
        if (StringUtils.isBlank(sort)) {
            sort = "asc";
        }
        MetaQuery paramQuery = new MetaQuery();
        paramQuery.addParam("uuid", strategy);
        if (StringUtils.isNotBlank(code)) {
            paramQuery.addParam("code", code);
        }
        OrderBy orderBy = new OrderBy(orderField, sort);
        paramQuery.setOrderByList(Lists.newArrayList(orderBy));
        paramQuery.setPage(new Page(index, 1));
        List<StrategyTradeDTO> list = metaDataDAO.queryListByCondition(OBJECT_CODE_STRATEGY_TRADE, paramQuery,
            StrategyTradeDTO.class);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        StrategyTradeDTO strategyTradeDTO = list.get(0);
        String buyDate = DateUtil.formatDate(strategyTradeDTO.getBuyDate());
        String sellDate = DateUtil.formatDate(strategyTradeDTO.getSellDate());
        String beginDate = DateUtil.formatDate(DateUtil.offsetDay(strategyTradeDTO.getBuyDate(), -period));
        String endDate = DateUtil.formatDate(DateUtil.offsetDay(strategyTradeDTO.getSellDate(), period));
        code = strategyTradeDTO.getCode();
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAllByDateRange(code, beginDate, endDate);

        List<StockKlineData> klineDatas = new ArrayList<>();
        StockDayData old = stockDayDataList.get(0);
        for (StockDayData data : stockDayDataList) {
            List kline = new ArrayList();
            kline.add(data.getOpenPrice());
            kline.add(data.getClosePrice());
            kline.add(data.getMinPrice());
            kline.add(data.getMaxPrice());
            kline.add(
                Objects.nonNull(data.getTradeNum()) ? data.getTradeNum().intValue() : old.getTradeNum().intValue());
            StockKlineData klineData = new StockKlineData();
            klineDatas.add(klineData);
            klineData.setCode(code);
            klineData.setData(data);
            klineData.setValue(kline);
            klineData.setStockDate(data.getDate());
            klineData.setVolume((Integer)kline.get(4));
            klineData.setUpOrDown(data.getClosePrice().compareTo(old.getClosePrice()) > 0 ? "y" : "n");
            klineData.setIndex(index);
            klineData.setRate(data.getRate());
            if (StringUtils.equals(data.getDate(), buyDate)) {
                klineData.setMark("买");
            } else if (StringUtils.equals(data.getDate(), sellDate)) {
                klineData.setMark("卖");
            }
        }
        //log.info("biasData:" + JSON.toJSONString(biasList));
        return klineDatas;
    }

    /**
     * 股票指标页面
     *
     * @return
     */
    @GetMapping(value = "/stockQuotaChart")
    public String stockQuotaChart() {
        return "stockQuotaChart";
    }

    /**
     * 获取股票日线数据的指标信息
     * eg:/api/stock/chart/stockQuotaChart?strategy=trend520&index=0&quota=obv
     *
     * @param
     * @return
     */
    @GetMapping(value = "/getStockQuotaData")
    @ResponseBody
    public List<StockKlineData> getStockQuotaData(String strategy, Integer period, Integer index, String orderField,
        String sort, String quota) {
        if (Objects.isNull(period)) {
            period = 100;
        }
        if (Objects.isNull(index)) {
            index = 0;
        }
        if (StringUtils.isBlank(orderField)) {
            orderField = "profit_rate";
        }
        if (StringUtils.isBlank(sort)) {
            sort = "asc";
        }
        MetaQuery paramQuery = new MetaQuery();
        paramQuery.addParam("uuid", strategy);
        Page page = new Page();
        page.setBegin(index);
        page.setLength(1);
        paramQuery.setPage(page);
        OrderBy orderBy = new OrderBy(orderField, sort);
        paramQuery.setOrderByList(Lists.newArrayList(orderBy));
        PageData<StrategyTradeDTO> pageData = metaDataDAO.queryPageByCondition(OBJECT_CODE_STRATEGY_TRADE, paramQuery,
            StrategyTradeDTO.class);

        if (CollectionUtils.isEmpty(pageData.getData())) {
            return null;
        }
        StrategyTradeDTO strategyTradeDTO = pageData.getData().get(0);
        String buyDate = DateUtil.formatDate(strategyTradeDTO.getBuyDate());
        String sellDate = DateUtil.formatDate(strategyTradeDTO.getSellDate());
        String beginDate = DateUtil.formatDate(DateUtil.offsetDay(strategyTradeDTO.getBuyDate(), -period));
        String endDate = DateUtil.formatDate(DateUtil.offsetDay(strategyTradeDTO.getSellDate(), period));
        String code = strategyTradeDTO.getCode();
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAllByDateRange(code, beginDate, endDate);
        List<StockKlineData> klineDatas = new ArrayList<>();
        doCalculateQuota(stockDayDataList, quota);
        StockDayData old = stockDayDataList.get(0);
        for (StockDayData data : stockDayDataList) {
            List kline = new ArrayList();
            kline.add(data.getOpenPrice());
            kline.add(data.getClosePrice());
            kline.add(data.getMinPrice());
            kline.add(data.getMaxPrice());
            kline.add(
                Objects.nonNull(data.getTradeNum()) ? data.getTradeNum().intValue() : old.getTradeNum().intValue());
            StockKlineData klineData = new StockKlineData();
            klineDatas.add(klineData);
            klineData.setCode(code);
            klineData.setData(data);
            klineData.setValue(kline);
            klineData.setStockDate(data.getDate());
            klineData.setVolume((Integer)kline.get(4));
            klineData.setUpOrDown(data.getClosePrice().compareTo(old.getClosePrice()) > 0 ? "y" : "n");
            klineData.setIndex(index);
            klineData.setRate(data.getRate());
            klineData.setQuota(Objects.nonNull(data.getQuota()) ? data.getQuota() : new JSONObject());
            if (StringUtils.equals(data.getDate(), buyDate)) {
                klineData.setMark("买");
            } else if (StringUtils.equals(data.getDate(), sellDate)) {
                klineData.setMark("卖");
            }

        }
        //log.info("biasData:" + JSON.toJSONString(biasList));
        return klineDatas;
    }

    private void doCalculateQuota(List<StockDayData> stockDayDataList, String quota) {
        if (StringUtils.equals(quota, OBVIndicator.QUOTA_NAME)) {
            OBVIndicator.calculateOBV(stockDayDataList);
        } else if (StringUtils.equals(quota, RSIIndicator.QUOTA_NAME)) {
            RSIIndicator.calculateRSI(stockDayDataList);
        }
    }

    /**
     * 股票信号图页面
     *
     * @return
     */
    @GetMapping(value = "/stockSignalChart")
    public String stockSignalChart() {
        return "stockSignalChart";
    }

    /**
     * 获取股票涨停信号日线数据
     * eg:/api/stock/chart/getAveragePrice?index=0&period=30&longPeriod=60
     *
     * @return
     */
    @GetMapping(value = "/getStockSignalData")
    @ResponseBody
    public List<StockKlineData> getStockSignalData(Integer index, String orderField, String sort, Integer period,
        Integer longPeriod, String code) {
        Integer yearPeriod = 250;
        if (Objects.isNull(period)) {
            period = 30;
        }
        if (Objects.isNull(longPeriod)) {
            longPeriod = 60;
        }
        if (Objects.isNull(index)) {
            index = 0;
        }
        if (StringUtils.isBlank(orderField)) {
            orderField = "two_month_later_high_rate";
        }
        if (StringUtils.isBlank(sort)) {
            sort = "desc";
        }
        MetaQuery metaQuery = new MetaQuery();
        metaQuery.setOrder(new OrderBy(orderField, sort));
        if (StringUtils.isNotBlank(code)) {
            metaQuery.addParam("code", code);
        } else {
            metaQuery.setPage(new Page(index, 1));
        }
        List<StockSignalDTO> stockSignalDTOList = metaDataDAO.queryListByCondition(OBJECT_CODE_STOCK_SIGNAL, metaQuery,
            StockSignalDTO.class);
        if (CollectionUtils.isEmpty(stockSignalDTOList)) {
            return null;
        }
        StockSignalDTO stockSignalDTO = stockSignalDTOList.get(0);
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(stockSignalDTO.getCode());
        MovingAverage.calculateEMA(stockDayDataList, period);
        MovingAverage.calculateEMA(stockDayDataList, longPeriod);
        MovingAverage.calculateEMA(stockDayDataList, yearPeriod);
        List<Date> signalDateList = stockSignalDTOList.stream().map(StockSignalDTO::getSignalDate).collect(
            Collectors.toList());
        Collections.sort(signalDateList, (o1, o2) -> o1.getTime() >= o2.getTime() ? 1 : -1);
        Date startDate = signalDateList.get(0);
        Date begin = DateUtil.offsetDay(startDate, -150);
        Date endDate = signalDateList.get(signalDateList.size() - 1);
        Date end = DateUtil.offsetDay(endDate, 120);
        List<String> dateList = signalDateList.stream().map(o -> DateUtil.formatDate(o)).collect(Collectors.toList());
        stockDayDataList = StockUtils.getStockDayDataListByDateRange(stockDayDataList, begin, end);
        for (StockDayData stockDayData : stockDayDataList) {
            if (dateList.contains(stockDayData.getDate())) {
                stockDayData.setMark("☆");
                continue;
            }
        }
        List<StockKlineData> klineDatas = new ArrayList<>();
        StockDayData old = stockDayDataList.get(0);

        for (StockDayData data : stockDayDataList) {
            List kline = new ArrayList();
            kline.add(data.getOpenPrice());
            kline.add(data.getClosePrice());
            kline.add(data.getMinPrice());
            kline.add(data.getMaxPrice());
            kline.add(
                Objects.nonNull(data.getTradeNum()) ? data.getTradeNum().intValue() : old.getTradeNum().intValue());
            StockKlineData klineData = new StockKlineData();
            klineData.setCode(stockSignalDTO.getCode());
            klineData.setData(data);
            klineData.setValue(kline);
            klineData.setStockDate(data.getDate());
            klineData.setVolume((Integer)kline.get(4));
            klineData.setUpOrDown(data.getClosePrice().compareTo(old.getClosePrice()) > 0 ? "y" : "n");
            klineData.setIndex(index);
            BigDecimal rate = data.getClosePrice().subtract(old.getClosePrice()).multiply(new BigDecimal(100)).divide(
                old.getClosePrice(), BigDecimal.ROUND_HALF_DOWN).setScale(2, RoundingMode.HALF_DOWN);
            klineData.setRate(rate);
            if (StringUtils.isNotBlank(data.getMark())) {
                klineData.setMark(data.getMark());
            }
            klineData.setShortAverageData(StockUtils.getAveragePrice(data, period));
            klineData.setLongAverageData(StockUtils.getAveragePrice(data, longPeriod));
            klineData.setYearAverageData(StockUtils.getAveragePrice(data, yearPeriod));
            klineDatas.add(klineData);
            old = data;
            index++;
        }
        //log.info("biasData:" + JSON.toJSONString(biasList));
        return klineDatas;
    }

    /**
     * 股票情绪图页面
     *
     * @return
     */
    @GetMapping(value = "/stockEmotion")
    public String stockEmotion() {
        return "stockEmotion";
    }

    /**
     * 股票情绪图页面
     *
     * @return
     */
    @GetMapping(value = "/stockEmotionSaveImage")
    public String stockEmotionSaveImage() {
        return "stockEmotionSaveImage";
    }

    /**
     * 获取股票涨停信号日线数据
     * eg:/api/stock/chart/getStockEmotionData?index=0&period=30&longPeriod=60
     *
     * @return
     */
    @GetMapping(value = "/getStockEmotionData")
    @ResponseBody
    public List<JSONObject> getStockEmotionData(String date) {
        if (StringUtils.isBlank(date)) {
            date = DateUtil.formatDate(new Date());
        }
        StockEmotion stockEmotion = stockEmotionService.getStockEmotion(date);
        if (Objects.isNull(stockEmotion)) {
            return null;
        }
        String datetime = date + DateUtils.BEIGN_TIME;
        List<JSONObject> list = new ArrayList<>();
        for (StockEmotion data : stockEmotion.getList()) {
            String emotionDatetime = data.getDatetime();
            if (DateUtils.before(emotionDatetime, datetime)) {
                continue;
            }
            JSONObject object = new JSONObject();
            object.put("time", emotionDatetime.split(" ")[1]);
            object.put("value", data.getCurrentValue());
            object.put("min", data.getMinValue());
            object.put("low", data.getLowValue());
            object.put("high", data.getHighValue());
            object.put("max", data.getMaxValue());
            list.add(object);

        }
        return list;
    }

    /**
     * 保存情绪图照片
     * eg:/api/stock/chart/saveStockEmotionImage
     *
     * @return
     */
    @PostMapping(value = "/saveStockEmotionImage")
    @ResponseBody
    public Result<UploadFileDTO> saveStockEmotionImage(HttpServletRequest request) {
        Date datetime=DateUtil.parseDateTime(DateUtil.formatDate(new Date())+DateUtils.BEIGN_TIME);
        if (DateUtils.before(new Date(),datetime)) {
            log.info("saveStockEmotionImage:{}-未开盘,忽略", DateUtil.formatDateTime(new Date()));
            return Result.getSuccessResult(null);
        }
        String body = ServletRequestUtils.getRequestBody(request);
        String[] params = body.split("&");
        String date = "";
        String imageData = "";
        for (String param : params) {
            if (param.startsWith("date")) {
                date = param.split("=")[1];
            } else if (param.startsWith("imageData")) {
                imageData = param.replace("imageData=", "");
            }
        }
        try {
            imageData = URLDecoder.decode(imageData, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String[] parts = imageData.split(",");
        String data = parts[1];
        byte[] imageBytes = Base64.getDecoder().decode(data);
        UploadFileDTO uploadFileDTO = HttpClientUtils.upload(UPLOAD_URL, new HashMap<>(), imageBytes,
            "情绪图_" + date + ".png");
        String fileUrl = String.format(DOWNLOAD_URL, uploadFileDTO.getResourceId());
        sendDingtalkImageMessage(fileUrl);
        return Result.getSuccessResult(uploadFileDTO);
    }

    public void sendDingtalkImageMessage(String url) {
        At at = new At();
        at.setIsAtAll(true);
        Markdown markdown = new Markdown();
        markdown.setTitle("情绪图通知");
        String imageContent = "![screenshot](" + url + ")\n";

        markdown.setText(
            "> " + imageContent + "> ##### 通知于"
                + DateUtil.formatDateTime(new Date())
                + "发布");
        dingTalkService.sendMessage(DING_TALK_URL, new DingTalkMessage(markdown, at));
    }

    @Data
    public static class HullAverageBias {
        private String date;
        private BigDecimal shortBias;
        private BigDecimal longBias;
    }

}
